#include "Task.hpp"
#include <queue>
#include <pthread.h>
#include "Log.hpp"

#define NUM 6

class Thread_Pool
{
private:
    int _num;
    std::queue<Task> _Task_Queue;
    pthread_mutex_t _lock;
    pthread_cond_t _cond;

    static Thread_Pool *sigle;

    Thread_Pool(int num = NUM) : _num(num)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    Thread_Pool(const Thread_Pool &thread_pool) = delete;

public:
    static Thread_Pool *GetInstance()
    {
        static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
        if (sigle == nullptr)
        {
            pthread_mutex_lock(&mtx);
            if (sigle == nullptr)
            {
                sigle = new Thread_Pool();
                sigle->InitThreadPool();
            }
            pthread_mutex_unlock(&mtx);
        }
        return sigle;
    }
    void Wait()
    {
        pthread_cond_wait(&_cond, &_lock);
    }

    void Wake()
    {
        pthread_cond_signal(&_cond);
    }

    void Lock()
    {
        pthread_mutex_lock(&_lock);
    }

    void Unlock()
    {
        pthread_mutex_unlock(&_lock);
    }

    bool Empty()
    {
        return _Task_Queue.empty();
    }

    void Push(const Task &task)
    {
        Lock();
        _Task_Queue.push(task);
        Unlock();
        Wake();
    }

    void Pop(Task &task)
    {
        task = _Task_Queue.front();
        _Task_Queue.pop();
    }

    static void *routine(void *args)
    {
        pthread_detach(pthread_self());
        Thread_Pool *tp = (Thread_Pool *)args;

        while (1)
        {
            tp->Lock();
            while (tp->Empty())
            {
                tp->Wait();
            }
            Task t;
            tp->Pop(t);
            tp->Unlock();

            t.ProcessOn();
        }
    }

    bool InitThreadPool()
    {
        for (int i = 0; i < _num; ++i)
        {
            pthread_t pid;
            if (pthread_create(&pid, nullptr, routine, (void *)this) != 0)
            {
                LOG(FATAL, "creat threadpoll error");
                return false;
            }
        }
        LOG(INFO, "creat thread poll success!");
        return true;
    }
    ~Thread_Pool()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }
};
Thread_Pool *Thread_Pool::sigle = nullptr;